/*
 * Copyright (c)  2016, dabing.io
 * All rights reserved.
 * OrderProcesser.java 2017-12-02 下午2:03
 */

package com.ueboot.weishop.api.component;

import com.ueboot.core.exception.BusinessException;
import com.ueboot.core.utils.DateUtils;
import com.ueboot.weishop.api.controller.order.vo.OrderReq;
import com.ueboot.weishop.common.CacheKeys;
import com.ueboot.weishop.entity.activity.ActivityEntity;
import com.ueboot.weishop.entity.activity.CrowResultEntity;
import com.ueboot.weishop.entity.customer.CustomerInvoiceEntity;
import com.ueboot.weishop.entity.customer.CustomerReceiverEntity;
import com.ueboot.weishop.entity.goods.GoodsInfoEntity;
import com.ueboot.weishop.entity.goods.GoodsSalesSpecEntity;
import com.ueboot.weishop.entity.order.*;
import com.ueboot.weishop.entity.setting.CategoryEntity;
import com.ueboot.weishop.service.activity.ActivityService;
import com.ueboot.weishop.service.activity.CrowResultService;
import com.ueboot.weishop.service.cache.CacheService;
import com.ueboot.weishop.service.customer.CustomerInvoiceService;
import com.ueboot.weishop.service.customer.CustomerReceiverService;
import com.ueboot.weishop.service.goods.GoodsSalesSpecService;
import com.ueboot.weishop.service.order.OrderExtensionService;
import com.ueboot.weishop.service.order.OrderService;
import com.ueboot.weishop.service.setting.CategoryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.RandomUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 描述:订单处理逻辑模块，用于抽取公用服务类
 *
 * @author yangkui create on 2017-12-02.
 * @since 1.0
 */
@Component
@Slf4j
public class OrderProcesser {

    @Autowired
    private CacheService cacheService;

    @Autowired
    private GoodsSalesSpecService goodsSalesSpecService;

    @Autowired
    private CategoryService categoryService;


    @Autowired
    private CustomerInvoiceService customerInvoiceService;

    @Autowired
    private CustomerReceiverService customerReceiverService;


    @Autowired
    private OrderService orderService;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private CrowResultService crowResultService;
    @Autowired
    private OrderExtensionService orderExtensionService;


    /**
     * 获取支付金额和限购份数
     *
     * @param actCountCacheKey
     * @param act
     * @param goods
     * @param req
     */
    public void getPayAmountAndLimitCount(String actCountCacheKey, ActivityEntity act, GoodsInfoEntity goods, OrderReq req) {
        //限购的库存数
        Integer limitCount = null;
        //支付金额
        Integer payAmount = 0;
        Long goodsInfoId = goods.getId();

        //库存统计方式，是根据活动，还是产品，还是规格
        String countKey = goodsInfoId + "";
        //3.校验库存
        if (ActivityEntity.TYPE_SEC_KILL.equals(act.getType())) {
            limitCount = act.getSeckillProvideCopies();
            //支付金额等于秒杀价格
            payAmount = act.getSeckillPrice();
        } else if (ActivityEntity.TYPE_CROW.equals(act.getType())) {
            limitCount = act.getCrowdUnit();
            //支付金额等于每份价格
            payAmount = act.getCrowUnitPrice();
            countKey = act.getPeriodNum();
        } else if (ActivityEntity.TYPE_DISCOUNT.equals(act.getType())) {
            //库存计算方式
            //根据规格或者规格代码统计
            if (ActivityEntity.STOCK_COUNT_TYPE_SPEC.equals(act.getStockCountType())
                    || ActivityEntity.STOCK_COUNT_TYPE_SPEC_SN.equals(act.getStockCountType())
                    || StringUtils.isEmpty(act.getStockCountType())) {
                //对限时折扣活动的库存校验
                Assert.notNull(req.getGoodsSalesSpecId(), "销售规格不能为空");
                if (goods.getActivity() == null || !goods.getActivity().getId().equals(act.getId())) {
                    cacheService.incrActOrderError(actCountCacheKey);
                    throw new BusinessException("104", "当前商品未参加该活动！");
                }
                //销售规格
                GoodsSalesSpecEntity goodsSalesSpec = goodsSalesSpecService.findById(req.getGoodsSalesSpecId());
                if (goodsSalesSpec == null) {
                    cacheService.incrActOrderError(actCountCacheKey);
                    throw new BusinessException("105", "当前商品销售规格不属于该商品！");
                }

                limitCount = goodsSalesSpec.getStock();
                payAmount = goodsSalesSpec.getPrice();
                //商品名称取至销售规格的具体名称
                String specName = goodsSalesSpec.getName();
                if (!StringUtils.isEmpty(specName)) {
                    goods.setName(specName);
                }

                //统计库存的方式
                if (ActivityEntity.STOCK_COUNT_TYPE_SPEC.equals(act.getStockCountType())) {
                    countKey = goodsSalesSpec.getId() + "";
                } else if (ActivityEntity.STOCK_COUNT_TYPE_SPEC_SN.equals(act.getStockCountType())) {
                    countKey = goodsSalesSpec.getSn();
                }
                //根据活动统计
            } else if (ActivityEntity.STOCK_COUNT_TYPE_ACT.equals(act.getStockCountType())) {
                //可以购买的总库存数量
                limitCount = act.getSeckillProvideCopies();
                payAmount = act.getDiscountOriginPrice();
                countKey = act.getSn();
            }

            // 根据优惠类型计算支付金额
            //折扣和直接支付金额两个值二选一
            Integer discountValue = act.getDiscountValue();
            Integer discountMinusPrice = act.getDiscountMinusPrice();
            if (discountValue != null) {
                if (discountValue >= 10 || discountValue <= 0) {
                    discountValue = 10;
                }
                payAmount = payAmount * discountValue / 10;
            } else if (discountMinusPrice != null) {
                //直接当定金使用
                payAmount = discountMinusPrice;
            }
            Assert.isTrue(!(discountValue == null && discountMinusPrice == null), "折扣和支付金额二者不能同时为空！");
        }
        req.setPayAmount(payAmount);
        req.setCountKey(countKey);
        req.setLimitCount(limitCount);

    }

    /**
     * 保存订单到数据库
     *
     * @param req
     * @param act
     * @param goods
     * @return
     */
    public OrderEntity saveOrder(OrderReq req, ActivityEntity act, GoodsInfoEntity goods) {
        Date orderTime = new Date();
        OrderEntity order = new OrderEntity();
        order.setOrderNo(req.getOrderNo());
        order.setMainImgUrl(goods.getMainImgUrl());
        order.setGoodsName(goods.getName());
        if (!StringUtils.isEmpty(req.getGoodsName())) {
            order.setGoodsName(req.getGoodsName());
        }
        order.setGoodsCount(req.getGoodsInfoCount());
        order.setCustomerOpenId(req.getOpenId());
        order.setOrderTime(orderTime);
        order.setActivitySN(act.getSn());
        order.setActivityName(act.getName());
        order.setActivityFullPathIds(goods.getActivityFullPathIds());
        order.setActivityFullPathName(goods.getActivityFullPathName());
        //使用活动规则信息当优惠信息展示给用户看
        order.setActivityContent(act.getRuleDesc());
        order.setOriginalPrice(goods.getOriginalPrice());
        order.setPayAmount(req.getPayAmount());
        order.setKeyForLimit(req.getKeyForLimit());
        order.setNeedInvoice(req.getNeedInvoice());
        order.setActivityType(act.getType());
        //支付有效时间5分钟
        Date payValidTime = DateUtils.getNextMinute(new Date(), 5);
        order.setPayValidTime(payValidTime);

        CategoryEntity category = categoryService.findById(goods.getCategory().getId());
        order.setCategoryName(category.getName());
        order.setCategoryCode(category.getCode());
        order.setCountKey(req.getCountKey());
        //TODO 优惠信息
        OrderItemEntity item = new OrderItemEntity();
        item.setMainImgUrl(goods.getMainImgUrl());
        //使用页面传的产品名称
        item.setGoodsName(goods.getName());
        if (!StringUtils.isEmpty(req.getGoodsName())) {
            item.setGoodsName(req.getGoodsName());
        }
        item.setCategory(goods.getCategory());
        if (goods.getOriginalPrice() != null) {
            item.setOriginalPrice(goods.getOriginalPrice());
        }
        item.setGoodsInfo(goods);
        item.setOrder(order);

        OrderExtensionEntity extensionEntity = new OrderExtensionEntity();
        extensionEntity.setCarType(req.getCarType());
        extensionEntity.setCustomerVin(req.getCustomerVin());
        extensionEntity.setTargetDealer(req.getTargetDealer());
        extensionEntity.setOrderNo(req.getOrderNo());
        extensionEntity.setCustomerOpenId(req.getOpenId());
        extensionEntity.setGoodsName(goods.getName());
        extensionEntity.setCategoryCode(category.getCode());
        if (!StringUtils.isEmpty(act.getPeriodNum())) {
            extensionEntity.setPeriodNum(act.getPeriodNum());
        }
        extensionEntity.setTargetDealerCode(req.getTargetDealerCode());

        //发票和邮件地址
        OrderInvoiceEntity orderInvoiceEntity = null;
        OrderReceiverEntity orderReceiverEntity = null;
        if (req.getAddressId() != null) {
            CustomerReceiverEntity receiverEntity = customerReceiverService.findById(req.getAddressId());
            orderReceiverEntity = new OrderReceiverEntity();
            BeanUtils.copyProperties(receiverEntity, orderReceiverEntity);
            orderReceiverEntity.setOrder(order);
        }
        if (req.getInvoiceId() != null) {
            CustomerInvoiceEntity invoiceEntity = customerInvoiceService.findById(req.getInvoiceId());
            orderInvoiceEntity = new OrderInvoiceEntity();
            BeanUtils.copyProperties(invoiceEntity, orderInvoiceEntity);
            orderInvoiceEntity.setOrder(order);
        }

        orderService.saveOrder(order, item, extensionEntity, orderInvoiceEntity, orderReceiverEntity);
        log.info("保存订单到DB成功:{}", req.getOrderNo());
        return order;
    }


    /**
     * 校验活动是否允许购买
     *
     * @param req
     * @param openId
     * @return
     */
    public ActivityEntity checkSubmitReq(OrderReq req, String openId) {
        if (StringUtils.isEmpty(openId)) {
            throw new BusinessException("000", "无法识别您的身份，请使用微信下单或者重新进入！");
        }

        ActivityEntity act = null;
        if (req.getActId() != null) {
            act = activityService.findById(req.getActId());
        } else {
            act = activityService.findBySn(req.getSn());
        }
        Assert.notNull(act, "活动代码或ID对应的活动不存在");
        //活动统计缓存key值
        String actCountCacheKey = act.getSn() + ":" + act.getId();
        cacheService.incrActCustomer(actCountCacheKey, openId);
        cacheService.incrActRequest(actCountCacheKey);
        //0.判断限购方式
        String keyForLimit = this.getKeyForLimit(act, openId, req);
        //不限购的情况下才判断
        if (!ActivityEntity.LIMIT_TYPE_NONE.equals(act.getLimitType())) {
            //只查询同一个活动代码的订单
            Map<String, String> orders = cacheService.findOrdersByKeyForLimit(act.getSn(), keyForLimit);
            //检查订单列表当中所有的订单状态，根据订单状态来决定是否已经超过可以购买的数量
            if (orders != null) {
                Integer count = 0;
                Integer unPayCount = 0;
                for (Map.Entry<String, String> entry : orders.entrySet()) {
                    String orderStatus = entry.getValue();
                    Integer goodsCount = orderService.findGoodsCountByOrderNo(entry.getKey());
                    //所有待支付的、支付完成的、支付中的，都计算为已经限购
                    if (OrderEnum.ORDER_STATUS_0.equals(orderStatus) ||
                            OrderEnum.ORDER_STATUS_1.equals(orderStatus)
                            || OrderEnum.ORDER_STATUS_2.equals(orderStatus)) {
                        count += goodsCount;
                    } else if (OrderEnum.ORDER_STATUS_3.equals(orderStatus)) {
                        redisTemplate.opsForHash().delete(CacheKeys.ACT_CUSTOMER_ORDER_LIST, entry.getKey());
                    }
                    if (OrderEnum.ORDER_STATUS_0.equals(orderStatus)) {
                        unPayCount += goodsCount;
                    }
                }
                log.info("openId:{},根据keyForLimit:{} 获取购买的订单数量:{}", openId, keyForLimit, orders.size());
                if (!ActivityEntity.LIMIT_TYPE_NONE.equals(act.getLimitType())) {
                    log.info("其中满足已经购买的订单数量:{},unPayCount:{}", count, unPayCount);
                    if (count + req.getGoodsInfoCount() > act.getLimitCopies()) {
                        cacheService.incrActOrderError(actCountCacheKey);
                        if (unPayCount > 0) {
                            throw new BusinessException("1001", "您在本次活动中还有未支付的订单!");
                        } else {
                            throw new BusinessException("100", "您已经在本次活动中已经购买过了，不能再次购买!");
                        }
                    }
                } else {
                    log.info("当前活动不限购用户可购买份数，可购买最大为库存数量。");
                }
            }
        }

        //1.判断活动状态
        //当前时间小于开始时间
        if (compare(new Date(), act.getStartTime()) < 0) {
            cacheService.incrActOrderError(actCountCacheKey);
            throw new BusinessException("1011", "当前活动尚未开始，无法参加!");
        }
        //当前时间小于开始时间
        if (compare(new Date(), act.getEndTime()) > 0) {
            cacheService.incrActOrderError(actCountCacheKey);
            throw new BusinessException("1012", "当前时间已经超过活动期限，无法参加!");
        }
        //2.状态为未开启时，无法参加
        if (!ActivityEntity.STATUS_OPENING.equals(act.getStatus())) {
            cacheService.incrActOrderError(actCountCacheKey);
            throw new BusinessException("102", "当前活动已经结束，无法继续参加!");
        }
        return act;
    }

    /**
     * 获取活动限购的方式对应的值
     *
     * @param act
     * @param openId
     * @param req
     * @return
     */
    public String getKeyForLimit(ActivityEntity act, String openId, OrderReq req) {
        //0.判断限购方式
        String keyForLimit = openId;
        if (!ActivityEntity.LIMIT_TYPE_NONE.equals(act.getLimitType())) {
            if (ActivityEntity.LIMIT_TYPE_VIN.equals(act.getLimitType())) {
                keyForLimit = req.getCustomerVin();
            } else if (ActivityEntity.LIMIT_TYPE_OPENID.equals(act.getLimitType())) {
                keyForLimit = req.getCustomerMobile();
            }
            Assert.notNull(keyForLimit, act.getLimitType() + "不能为空");
        } else {
            keyForLimit = ActivityEntity.LIMIT_TYPE_NONE;
        }
        return keyForLimit;
    }


    public long compare(Date startDate, Date endDate) {
        long startTime = startDate.getTime();
        long endTime = endDate.getTime();
        return startTime - endTime;
    }

    /**
     * 执行开奖逻辑，从所有抽奖号码当中随机选择一个号码进行开奖
     * 1.更新抽奖记录
     * 2.更新期次信息
     * 3.更新订单信息
     *
     * @param act       活动代码
     * @param periodNum 期次代码
     * @return
     */
    public String executeOpenLottery(ActivityEntity act, String periodNum) {
        List<CrowResultEntity> results = crowResultService.findByActivityCodeAndPeriodNum(act.getSn(), periodNum);
        //随机取一个当中奖号码
        int index = RandomUtils.nextInt(results.size()) - 1;
        log.info("可以抽奖的数量:{},抽中的下标:{}", results.size(), index);
        if (index < 0) {
            index = 0;
        }
        CrowResultEntity crow = results.get(index);
        Date lotteryDate = new Date();
        crow.setOpenDate(lotteryDate);
        //只有代金券才下发dms
        if (act.getName().indexOf("代金券") > -1) {
            crow.setIssueDms(CrowResultEntity.ISSUE_DMS_1);
        }
        crow.setLottery(CrowResultEntity.LOTTERY_YES);
        this.crowResultService.save(crow);
        //更新订单开奖状态
        OrderExtensionEntity o = orderExtensionService.findByOrderNo(crow.getOrderNo());
        o.setLottery(OrderExtensionEntity.LOTTERY_YES);
        orderExtensionService.save(o);
        //更新其他未中奖
        results.forEach((entity) -> {
            if (!entity.getId().equals(crow.getId())) {
                entity.setLottery(CrowResultEntity.LOTTERY_NO);
                entity.setOpenDate(lotteryDate);
                this.crowResultService.save(crow);
                //更新订单开奖状态
                OrderExtensionEntity a = orderExtensionService.findByOrderNo(entity.getOrderNo());
                a.setLottery(OrderExtensionEntity.LOTTERY_NO);
                orderExtensionService.save(a);
            }
        });


        //更新活动期次信息
        String newperiodNum = cacheService.incrPeriodNum(act.getSn());
        log.info("新的期次号码为:{}", newperiodNum);
        act.setPeriodNum(newperiodNum);
        activityService.updateActivityEntity(act);
        return crow.getLotteryNum();
    }


}